package edu.hcmus.sow.domain.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

import edu.hcmus.sow.dao.UserGroupDAO;
import edu.hcmus.sow.domain.UserGroup;

public class CustomSidRetrievalStrategyImpl extends SidRetrievalStrategyImpl {

   @Autowired
   UserGroupDAO userGroupDAO;

   private RoleHierarchy roleHierarchy = new NullRoleHierarchy();

   public CustomSidRetrievalStrategyImpl() {
   }

   public CustomSidRetrievalStrategyImpl(RoleHierarchy roleHierarchy) {
      Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
      this.roleHierarchy = roleHierarchy;
   }

   // ~ Methods
   // ========================================================================================================

   @Override
   public List<Sid> getSids(Authentication authentication) {
      Collection<? extends GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication
            .getAuthorities());
      int userID = ((CustomUser) authentication.getPrincipal()).getUserID();

      List<UserGroup> groups = userGroupDAO.findByUserID(userID);

      List<Sid> sids = new ArrayList<Sid>(authorities.size() + groups.size() + 1);

      sids.add(new CustomPrincipalSid(authentication));

      for (UserGroup group : groups) {
         sids.add(new GroupSid(group.getGroupID().toString()));
      }

      for (GrantedAuthority authority : authorities) {
         sids.add(new GrantedAuthoritySid(authority));
      }

      return sids;
   }
}
